iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0

在第 1 天,我們用一條看似極簡的公式作為起點:

Agent = Model + Context + Tools + Loop

這四個要素各自對應一塊工程責任。走過這 30 天從底層 API、狀態圖、意圖分流、檢索優化、人工審核,到評估與觀測的完整實作,我們得到的最重要認知是:這條公式始終沒變,但我們對每個字底層的工程邊界,有了截然不同的理解。

當模型本質上具備隨機性與不確定性時,系統的穩定性與可靠性無法靠運氣堆疊,必須完全來自確定性的軟體工程。這 30 天的所有設計模式,本質上都在回答同一個問題:如何用確定性的程式碼,在四個維度替非確定性的模型築起不可逾越的邊界?

1. Model

在最開始,我們讓模型自由輸出文本;但到了生產環境,我們學會了最核心的一條防線:模型的輸出視為「提議」,先經程式驗證才進入業務邏輯;會改變真實資料的操作,決定權留在程式與人工審核手上。

  • 以強型別收斂自由語意:我們不再接收模型的自由字串,而是使用 Pydantic 與 Enum 定義嚴格的型別白名單。使用者的意圖被限縮在有限的列舉值中(例如查詢訂單、申請退貨、轉接真人);一旦模型判斷信心不足、缺少必要欄位或格式不符,直接在邊界標記為待釐清,徹底阻斷隨機猜測流入業務邏輯。
  • 資料操作權限徹底隔離:我們不讓模型直接生成 SQL 或自由查詢語句,而是設計查詢規格物件(QuerySpec)。模型僅負責將使用者的自然語言映射為白名單欄位與運算子,後續的語句組裝、權限校驗與資料庫執行全部由確定性程式碼接手。
  • 狀態與記憶的寫入防護:對話中抽取出的長期偏好,必須經由型別與鍵值白名單過濾後才能持久化,防止自由文字污染記憶庫。
  • 評估器的輸入隔離:即使讓 LLM 擔任評判者(LLM-as-a-Judge),我們也必須嚴格限縮其上下文,只提供確認的事實依據與最終回覆,將中間思考過程與系統日誌隔離在外,防止評估器本身受到推論雜訊干擾。

2. Context

最直覺的對話實作,是將上一輪的歷史訊息原封不動附加到下一輪的請求中。但底層的 Messages API 本身是無狀態的,若僅是線性累積歷史,很快就會帶來 Context 雜訊增加、Token 成本攀升與快取命中率下降的問題。管理 Context 的核心,在於儲存層(State)與呈現層(Context)的職責分離:

  • 狀態保存與決策輸入裁剪:狀態庫(Checkpointer)依會話識別碼(thread_id)完整持久化所有執行軌跡與資料歷史;但每次送進模型決策的 Context 必須動態裁剪,只投影當輪決策所需的最小資訊。這不僅控制了推論延遲與 Token 成本,也大幅提升了 Prompt 快取的命中率。
  • 知識檢索的階梯式權衡:外部知識注入 Context 的方式不能一概而論,我們建立了成本與精準度的分級意識:
    • 單一事實查詢:採用固定 RAG 檢索管線,以最低延遲直接取得相關片段。
    • 複合與不確定問題:引入 Agentic RAG,由模型根據上下文判斷是否需要檢索、如何重寫查詢關鍵字,並由驗證節點檢查檢索證據是否充分,不足時禁止腦補。
    • 跨文件實體關聯:只有當問題涉及多篇文件之間的實體跳躍時,才動用成本最高的 GraphRAG 進行圖譜路徑查詢。
  • 記憶的時間維度切分:短期會話記憶隨執行緒自動存取;長期偏好則在對話結束後非同步提煉為結構化標籤,在未來的對話中依使用者識別碼(user_id)精準投影回 Context,不再搬運冗長無序的歷史文本。

3. Tools

工具不是單純「讓模型多呼叫一個函式」,它是模型干預真實世界的觸手。因為帶有副作用,執行的主導權必須永遠留在程式手中:

  • 請求與執行的嚴密配對:模型送出的 Tool Call 只是結構化參數請求,系統透過唯一配對識別碼(如 tool_use_id)精確校驗請求與執行結果。無論工具是本地函式還是透過 MCP 接入的外部伺服器,契約與責任邊界保持一致。
  • 人工審核(HITL)的高風險攔截:退款、資料刪除、權限變更等高風險操作,不能放任模型自主閉環。我們利用中斷機制(如 interrupt())在工具執行前暫停狀態推進,等待人工審核或補充資訊;當流程被喚醒恢復執行時,程式端必須重新校驗參數,不盲目信任先前暫存的輸出。
  • 安全防禦:非信任輸入在進入模型前先行脫敏;工具調用權限依已確認的意圖實施最小權限隔離;模型輸出則由程式依工具實際回傳的事實逐欄比對,徹底防止幻覺內容外溢造成實質損害。

4. Loop

當我們用狀態圖(Node、Edge、State)取代散落各處的條件判斷時,決策循環才真正具備了工程可控性。但在管理自主循環時:模型說「完成了」,不代表任務真的完成。

  • 以客觀業務事實判定終止:模型停止產生 Tool Call 僅代表它當下覺得說完了,系統判定結案的標準,必須依據 State 中記錄的客觀業務欄位是否齊全、必要回執是否已確認,同時設定業務呼叫上限與框架遞迴保護(recursion_limit),防止 Agent 陷入死循環或過早放棄。
  • 超出單一循環負載時的架構拆分:當任務長度或複雜度超出單一 Context 容納極限時,我們不再勉強單一模型,也不放任多個模型自由對話,而是演進為 Orchestrator-Subagent 架構。各 Sub-Agent 在各自乾淨獨立的 Context 內專注單一子任務,透過嚴格的結構化契約(任務指派與結果交付)交接;大型檔案產物則透過識別碼引用,不讓繁雜的中間細節污染全域決策流。

5. 評估與觀測:從零散驗收到工程閉環

在系列文章的最後,我們不再只依賴零星的手動測試,而是建立起三層系統化的驗證體系:

  • 確定性邏輯的單元測試:路由分流、狀態轉移邏輯、Pydantic 型別防護等屬於純程式碼,我們使用傳統測試工具(如 pytest)建立零推論成本、毫秒級的自動化回歸測試。
  • 非確定性品質的離線評估:針對回答正確度與事實忠實度,建立固定的黃金測試集,搭配輸入隔離的 LLM Judge 進行離線自動化批次評估,作為發布前不可妥協的品質門檻。
  • 線上追蹤與異常閉環:生產環境透過完整 Trace 記錄每一次調用的輸入、路由決策、工具執行軌跡與耗時(如串接 Langfuse)。線上收集到的異常與失敗案例,經標註後持續回補至離線測試集,形成監控、診斷與修復的長效閉環。

一個能回答問題的語言模型,距離一個能在生產環境自主完成任務的 AI Agent,中間隔著的是這 30 天裡我們寫下的每一道工程邊界。

這道邊界的本質,在於認清系統的定位:我們打造的是具有特定目的、邊界明確的 Agent。

這些特定目的——無論是意圖的結構化驗證、關鍵欄位的格式檢查,還是「退款必須持有單號」、「意圖不明時不能盲目放行」、「缺漏需求最多只能追問兩次」等規則——正是系統的業務核心。如果將這些業務規則與邊界決策全交給 AI 自由決定,系統便會失去生產環境所必需的可預測性。

系統的核心價值與安全邊界,必須由工程師透過確定性的程式碼(Pydantic 模型、狀態圖與 Router 條件分流)明確表達並強制執行。AI 的職責在於提供自然語言理解與彈性生成的輔助,狀態轉移與控制權限則牢牢掌握在程式手中。兩者各司其職:AI 負責理解與提議,程式負責驗證與控制。Agent 才能在保有對話彈性的同時,具備生產環境所必需的穩定度與可預測性。

語言模型賦予了系統理解自然語言與彈性推理的能力,但真正讓系統能夠上線、承擔業務責任並經受異常考驗的,是型別安全、狀態機管理、人工審核、契約拆分與觀測閉環。當你帶著這套架構去構建下一個真實世界的 Agent 時,只要這四道邊界依然清晰,出錯時你能從 Trace 找到原因,把失敗案例補進測試集,系統的行為就能持續收斂在可預期的範圍內。

以上就是這個 30 天系列的全部內容,希望對讀者在開發AI Agent時能有幫助。


上一篇
用 Langfuse 建立 Agent 稽核紀錄與異常監控
系列文
AI Agent 系統開發 30 天 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言